/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.kramerius.articles.importFromLn.articleImport;

import cz.mzk.kramerius.articles.importFromLn.PropertyNames;
import cz.mzk.kramerius.articles.importFromLn.krameriusAccess.Repository;
import cz.mzk.kramerius.commons.PropertyLoader;
import cz.mzk.kramerius.commons.RandomBasedUuidGenerator;
import cz.mzk.kramerius.commons.UuidGenerator;
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

/**
 *
 * @author Martin Řehánek (rehan@mzk.cz)
 */
public class Rollbacker {

    private static final Logger logger = Logger.getLogger(Rollbacker.class.getName());
    private static final XPath articlePath = DocumentHelper.createXPath("article");
    private static final XPath volumePidPath = DocumentHelper.createXPath("volume/@PID");
    private static final XPath issuePidPath = DocumentHelper.createXPath("issue/@PID");
    private final File importLogDir;
    private final Repository repository;

    /**
     * Factory method for creating instances of Importer
     *
     * @param properties
     */
    public static Rollbacker instanceOf(PropertyLoader properties) throws Exception {
        UuidGenerator uuidGenerator = RandomBasedUuidGenerator.instanceOf();
        //EthAddrUuidGenerator.instanceOf(properties);
        if (uuidGenerator == null) {
            throw new Exception("Could not initiate  " + uuidGenerator.getClass().getName());
        }
        Repository repository = Repository.instanceOf(properties);
        if (repository == null) {
            throw new Exception("Could not initiate  " + repository.getClass().getName());
        }
        File importLogDir = properties.loadDir(PropertyNames.ROLLBACK_IMPORT_LOG_DIR, true, false, true);
        return new Rollbacker(repository, importLogDir);
    }

    private Rollbacker(Repository repository, File importLogDir) {
        this.repository = repository;
        this.importLogDir = importLogDir;
    }

    /**
     * Restores Repository to the state before importing all the articles that
     * have their import logs stored in directory defined in properties
     *
     * @return number of articles removed
     */
    public int rollbackAllArticleImports() {
        if (!importLogDir.isDirectory()) {
            logger.log(Level.SEVERE, "File ''{0}'' is not a directory ", importLogDir.getAbsolutePath());
            return 0;
        } else if (!importLogDir.canRead()) {
            logger.log(Level.SEVERE, "Cannot read directory ''{0}''", importLogDir.getAbsolutePath());
            return 0;
        }
        File[] importLogFiles = importLogDir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return !name.startsWith(".");
            }
        });
        for (File file : importLogFiles) {
            rollbackArticleImport(file);
        }
        return importLogFiles.length;
    }

    /**
     * Restores Repository to the state before importing the article.
     *
     * @param articlePid pid of imported article. File with import log is
     * searched for in directory defined in properties
     */
    public void rollbackArticleImport(String articlePid) {
        rollbackArticleImport(createImportLogFile(articlePid));
    }

    private File createImportLogFile(String articlePid) {
        StringBuilder importLogFilename = new StringBuilder();
        importLogFilename.append(importLogDir);
        importLogFilename.append(File.separatorChar);
        importLogFilename.append(articlePid);
        importLogFilename.append(".xml");
        return new File(importLogFilename.toString());
    }

    /**
     * Restores Repository to the state before importing the article.
     *
     * @param importLogFile file with import log
     */
    public void rollbackArticleImport(File importLogFile) {
        try {
            SAXReader reader = new SAXReader();
            Document doc = reader.read(importLogFile);
            Element articleEl = (Element) articlePath.selectSingleNode(doc);
            String articlePid = articleEl.attributeValue("PID");
            Set<String> volumes = volumesOfArticle(articleEl);
            Set<String> issues = issuesOfArticle(articleEl);
            repository.removeArticle(articlePid, volumes, issues);
        } catch (DocumentException ex) {
            Logger.getLogger(Importer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private Set<String> volumesOfArticle(Element articleEl) {
        List<Node> volumePidNodes = volumePidPath.selectNodes(articleEl);
        Set<String> result = new HashSet<String>(volumePidNodes.size());
        for (Node volumePidNode : volumePidNodes) {
            String volumePid = volumePidNode.getText();
            result.add(volumePid);
        }
        return result;
    }

    private Set<String> issuesOfArticle(Element articleEl) {
        List<Node> issuePidNodes = issuePidPath.selectNodes(articleEl);
        Set<String> result = new HashSet<String>(issuePidNodes.size());
        for (Node issuePidNode : issuePidNodes) {
            String issuePid = issuePidNode.getText();
            result.add(issuePid);
        }
        return result;
    }
}
